package com.qq.vip.mikuPy2001.bukkit.gui.model;

import com.qq.vip.mikuPy2001.bukkit.gui.util.ItemUtil;
import com.qq.vip.mikuPy2001.bukkit.gui.util.Message;
import com.qq.vip.mikuPy2001.bukkit.gui.privater.PrivateModule;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.List;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.inventory.ItemStack;

/**
 *
 * @author MukiPy2001
 */
public abstract class Module extends PrivateModule {

    private static final HashMap<String, Constructor> constructormap = new HashMap<>();

    /**
     * 清空个性化 Module. 本方法由本插件在被注销时自动调用. 无需手动调用.
     */
    public final static void close() {
        constructormap.clear();
    }

    /**
     * 注册一个个性化的 Module. 当配置文件中申明类型为 typeName 时,尝试使用指定的 clazz 去加载.
     *
     * @param typeName 类型
     * @param clazz class类
     * @return
     */
    public final static boolean register(String typeName, Class<? extends Module> clazz) {
        Constructor<?>[] constructors = clazz.getConstructors();
        if (!Module.class.isAssignableFrom(clazz)) {
            Message.debug("注册|控件|失败|不是一个控件|" + typeName);
            return false;
        }
        for (Constructor<?> constructor : constructors) {
            Class<?>[] parameterTypes = constructor.getParameterTypes();
            if (parameterTypes.length != 2) {
                Message.debug("注册|控件|忽略|不是两个参数|" + typeName);
                continue;
            }
            Class parameterClass = parameterTypes[0];
            Message.debug("详细|控件|参数一|" + parameterClass.getCanonicalName());
            if (String.class != parameterClass) {
                Message.debug("注册|控件|忽略|参数一不为String|" + typeName);
                continue;
            }
            parameterClass = parameterTypes[1];
            Message.debug("详细|控件|参数二|" + parameterClass.getCanonicalName());
            if (!ConfigurationSection.class.isAssignableFrom(parameterClass)) {
                Message.debug("注册|控件|忽略|参数二不为ConfigurationSection|" + typeName);
                continue;
            }
            constructormap.put(typeName.toLowerCase(), constructor);
            Message.debug("注册|控件|成功|" + typeName);
            return true;
        }
        Message.debug("注册|控件|失败|找不到需要的构造函数|" + typeName);
        return false;
    }

    /**
     * 从配置文件获取 Module 的工厂方法
     *
     * @param ModuleID Module 唯一ID
     * @param con 配置文件
     * @return 指定类型的Module
     */
    public final static Module loadFromConfiguration(String ModuleID, ConfigurationSection con) {
        try {
            String type, lowerCasetype;
            if (con.contains("type"))
                type = con.getString("type");
            else
                type = "UnknowType";

            lowerCasetype = type.toLowerCase();
            switch (lowerCasetype) {
                case "editbox":
                    return new EditBox(ModuleID, con);
                case "button":
                    return new Button(ModuleID, con);
                default:
                    Constructor get = constructormap.get(lowerCasetype);
                    if (get != null)
                        return (Module) get.newInstance(ModuleID, con);
                    Message.warn("Unknow type in [" + ModuleID + "], it's type is " + type);
                    return null;
            }
        } catch (Throwable e) {
            Message.warn("A Exception in load [" + ModuleID + "]", e);
            return null;
        }
    }

    protected final int index;
    protected final String moduleID;
    protected final boolean show;

    /**
     * 从配置文件加载. 详细格式请查阅示例
     *
     * @param ModuleID Module 的唯一ID
     * @param con
     */
    protected Module(String ModuleID, ConfigurationSection con) {
        this(ModuleID,
                initializationIndex(con),
                con.isConfigurationSection("item") ? ItemUtil.loadFromConfiguration(con.getConfigurationSection("item")) : null,
                con.getBoolean("show"));
        Message.debug("加载|" + this);
    }

    /**
     * 根据平面坐标定义Module的位置
     *
     * @param ModuleID Module 的唯一ID
     * @param line Module 所在行数,起始为1
     * @param lineIndex Module 所在列数,起始为1
     * @param itemStack Module 显示的图标
     */
    protected Module(String ModuleID, int line, int lineIndex, ItemStack itemStack) {
        this(ModuleID, line, lineIndex, itemStack, false);
    }

    /**
     * 根据箱子内部位置系统定义Module的位置
     *
     * @param ModuleID Module 的唯一ID
     * @param index Module 所在的位置
     * @param itemStack Module 显示的图标
     */
    protected Module(String ModuleID, int index, ItemStack itemStack) {
        this(ModuleID, index, itemStack, false);
    }

    /**
     * 根据平面坐标定义Module的位置
     *
     * @param ModuleID Module 的唯一ID
     * @param line Module 所在行数,起始为1
     * @param lineIndex Module 所在列数,起始为1
     * @param itemStack Module 显示的图标
     * @param show
     */
    protected Module(String ModuleID, int line, int lineIndex, ItemStack itemStack, boolean show) {
        this(ModuleID, (line - 1) * 9 + lineIndex - 1, itemStack, show);
    }

    /**
     * 根据箱子内部位置系统定义Module的位置
     *
     * @param ModuleID Module 的唯一ID
     * @param index Module 所在的位置
     * @param itemStack Module 显示的图标
     * @param show
     */
    protected Module(String ModuleID, int index, ItemStack itemStack, boolean show) {
        this.moduleID = ModuleID;
        this.index = index;
        this.show = show;
        setItemStack0(itemStack);

        if (index < 0)
            throw new RuntimeException("位置小于0 : " + index);
        if (ModuleID == null)
            throw new RuntimeException("ModuleID 为 null");
        if (ModuleID.trim().isEmpty())
            throw new RuntimeException("ModuleID 为 空");
    }

    private static int initializationIndex(ConfigurationSection con) {
        if (con.isInt("index")) {
            return con.getInt("index");
        } else if (con.isList("index")) {
            List<Integer> integerList = con.getIntegerList("index");
            if (integerList.size() == 2) {
                return (integerList.get(0) - 1) * 9 + integerList.get(1) - 1;
            } else
                throw new RuntimeException("index is intlist but size not is 2 in Configuration, size is:" + integerList.size());

        } else {
            throw new RuntimeException("no found index in Configuration");
        }
    }

    /**
     * 刷新本控件. 直接操作物品后. 建议调用本方法
     *
     */
    public void updateToInv() {
        if (getView() == null || !isEnable())
            return;
        getView().update(this);
    }

    /**
     * 刷新本控件. 直接操作物品后. 建议调用本方法
     *
     */
    public void updateFromInv() {
        if (getView() == null || !isEnable())
            return;
        getView().update(getIndex());
    }

    /**
     * 这个用于指示在界面创建时是否显示本控件.
     *
     * @return
     */
    public boolean CanShowOnCreate() {
        return show;
    }

    /**
     * 获得本控件在界面的绝对位置
     *
     * @return
     */
    public final int getIndex() {
        return index;
    }

    /**
     * 获取本控件所表示的图标
     *
     * @return
     */
    public ItemStack getItemStack() {
        return (getView() == null || !isEnable()) ? getItemStack0()
                : getView().getItem(getIndex());
    }

    /**
     * 设置新的图标.
     *
     * @param itemStack
     */
    public void setItemStack(ItemStack itemStack) {
        setItemStack0(itemStack);
        if (getView() != null)
            getView().update(this);
    }

    /**
     * 获取本控件的唯一ID. 仅本界面唯一.
     *
     * @return
     */
    public String getModuleID() {
        return moduleID;
    }

    /**
     * 组件事件. 当玩家打开界面时,此方法被调用一次.
     *
     */
    @Override
    public void init() {
    }

    /**
     * 激活事件. 当控件被激活时此方法会被调用
     *
     */
    @Override
    public void enable() {
    }

    /**
     * 注销事件. 当控件被激活时此方法会被调用
     *
     */
    @Override
    public void disable() {
    }

    /**
     * 改良的toString方法用于debug
     *
     * @return
     */
    @Override
    public String toString() {
        return "[" + getClass().getSimpleName() + ", ID:" + moduleID + ", Index:" + index + "]"; //To change body of generated methods, choose Tools | Templates.
    }

}
